package kz.pompei.oneGwtStands.client.stand;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import kz.pompei.OneGwt.ifaces.util.Dummy;
import kz.pompei.OneGwt.ifaces.util.Handler;
import kz.pompei.OneGwt.ifaces.util.StrSetter;
import kz.pompei.OneGwt.ifaces.widget.HasStandart;
import kz.pompei.oneGwtStands.client.remote.AsyncTimer;

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class Stand {
  
  private StrSetter log = Dummy.doNothing_s();
  private Handler clearLog = Dummy.noHandler();
  
  public void log(String message) {
    log.set( message );
  }
  
  public void clearLog() {
    clearLog.handle();
  }
  
  private boolean wasRun = false;
  
  private final List<MenuInjector> menuInjectors = new ArrayList<Stand.MenuInjector>();
  
  private PublicMenuBar mainMenuBar;
  
  private Widget source;
  
  private static class MenuInjector {
    String menuPath;
    Handler handler;
    
    public MenuInjector(String menuPath, Handler handler) {
      super();
      this.menuPath = menuPath;
      this.handler = handler;
    }
  }
  
  public void injectMenuItem(String menuPath, Handler handler) {
    MenuInjector x = new MenuInjector( menuPath, handler );
    if (wasRun) {
      innerInjectMenuItem( x );
    } else {
      menuInjectors.add( x );
    }
  }
  
  public void run() {
    if (wasRun) throw new IllegalStateException( "Stand already run" );
    
    PublicMenuBar menu = new PublicMenuBar();
    // menu.setStyleName( "stand-menu" );
    
    RootPanel.get().add( menu );
    
    mainMenuBar = menu;
    
    for (MenuInjector x : menuInjectors) {
      innerInjectMenuItem( x );
    }
    menuInjectors.clear();
    wasRun = true;
    
    if (source != null) {
      RootPanel.get().add( source );
    }
    {
      final VerticalPanel forLogs = new VerticalPanel();
      forLogs.addStyleName( "stand-forLogs" );
      RootPanel.get().add( forLogs );
      
      final List<Widget> added = new ArrayList<Widget>();
      
      log = new StrSetter() {
        @Override
        public void set(String message) {
          String dat = DateTimeFormat.getFormat( "yyyy-MM-dd HH:mm:ss.SSS" ).format( new Date() );
          
          Label w = new Label( "[" + dat + "] " + message );
          w.addStyleName( "stand-forLogs-label" );
          
          added.add( w );
          forLogs.add( w );
        }
      };
      
      clearLog = new Handler() {
        @Override
        public void handle() {
          for (Widget widget : added) {
            forLogs.remove( widget );
          }
          added.clear();
        }
      };
    }
    
    injectMenuItem( "stand->clear log", clearLog );
    injectTimeMenuItems();
  }
  
  private void injectTimeMenuItems() {
    injectMenuItem( "stand->server time->1 --- 1", new Handler() {
      @Override
      public void handle() {
        AsyncTimer.time1 = 1;
        AsyncTimer.time2 = 1;
      }
    } );
    
    injectMenuItem( "stand->server time->1000 --- 1000", new Handler() {
      @Override
      public void handle() {
        AsyncTimer.time1 = 1000;
        AsyncTimer.time2 = 1000;
      }
    } );
    
    injectMenuItem( "stand->server time->1 --- 1000", new Handler() {
      @Override
      public void handle() {
        AsyncTimer.time1 = 1;
        AsyncTimer.time2 = 1000;
      }
    } );
    
    injectMenuItem( "stand->server time->1000 --- 1", new Handler() {
      @Override
      public void handle() {
        AsyncTimer.time1 = 1000;
        AsyncTimer.time2 = 1;
      }
    } );
    
  }
  
  private void innerInjectMenuItem(MenuInjector x) {
    String[] menus = x.menuPath.split( "->" );
    inject( mainMenuBar, menus, 0, x );
  }
  
  private void inject(PublicMenuBar menuBar, String[] menus, int index, MenuInjector x) {
    if (index >= menus.length) {
      throw new IllegalArgumentException( "index = " + index + ", menus.length = " + menus.length );
    }
    if (index == menus.length - 1) {
      final Handler finalHandler = x.handler;
      menuBar.addItem( menus[index].trim(), new Command() {
        @Override
        public void execute() {
          new Timer() {
            @Override
            public void run() {
              finalHandler.handle();
            }
          }.schedule( 100 );
        }
      } );
      return;
    }
    PublicMenuBar subMenuBar = findOrCreateSubMenuBar( menuBar, menus[index].trim() );
    inject( subMenuBar, menus, index + 1, x );
  }
  
  private PublicMenuBar findOrCreateSubMenuBar(PublicMenuBar menuBar, String menuTitle) {
    for (MenuItem menuItem : menuBar.getItems()) {
      if (menuTitle.equals( menuItem.getText() )) {
        return (PublicMenuBar)menuItem.getSubMenu();
      }
    }
    {
      PublicMenuBar ret = new PublicMenuBar( true );
      menuBar.addItem( menuTitle, ret );
      return ret;
    }
  }
  
  public void setSource(Widget source) {
    this.source = source;
  }
  
  public void injectStandart(String prefix, final HasStandart widget) {
    for (final boolean b : new boolean[] { false, true }) {
      injectMenuItem( prefix + "->setEnabled->" + b, new Handler() {
        @Override
        public void handle() {
          widget.setEnabled( b );
        }
      } );
      injectMenuItem( prefix + "->setVisible->" + b, new Handler() {
        @Override
        public void handle() {
          widget.setVisible( b );
        }
      } );
      injectMenuItem( prefix + "->setFocus->" + b, new Handler() {
        @Override
        public void handle() {
          widget.setFocus( b );
        }
      } );
    }
  }
}
